using FileServer.Abstractions;
using FileServer.Abstractions.Models;
using FileServer.Abstractions.Models.Result;
using FileServer.Abstractions.VirtualFileServer;
using Gateway.IApplication.UploadFiles.Output;
using Microsoft.Extensions.DependencyInjection;
using System.IO;

namespace FileServer.Extension;

/// <summary>
/// 文件操作
/// </summary>
public class FileOperator : IFileOperator
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public FileOperator(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }
    /// <summary>
    /// 从文件流上传文件
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<UploadResult> UploadAsync(UploadFileInputStream input)
    {
        if (string.IsNullOrEmpty(input.StorageKey))
        {
            input.StorageKey = FileUploadProvider.GetDefaultFileProviderOptions()?.StorageKey;
        }
        IFileUpload service = GetService(input.StorageKey);
        return await service.UploadAsync(input);
    }
    /// <summary>
    /// 从文件中上传文件
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<UploadResult> UploadAsync(UploadFileInputForm input)
    {
        if (string.IsNullOrEmpty(input.StorageKey))
        {
            input.StorageKey = FileUploadProvider.GetDefaultFileProviderOptions()?.StorageKey;
        }
        IFileUpload service = GetService(input.StorageKey);
        return await service.UploadAsync(input);
    }
    /// <summary>
    /// 从远程上传文件
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<UploadResult> UploadAsync(UploadFileInputRemote input)
    {
        if (string.IsNullOrEmpty(input.StorageKey))
        {
            input.StorageKey = FileUploadProvider.GetDefaultFileProviderOptions()?.StorageKey;
        }
        IFileUpload service = GetService(input.StorageKey);
        return await service.UploadAsync(input);
    }
    /// <summary>
    /// 删除文件
    /// </summary>
    /// <param name="fileUrl"></param>
    /// <returns></returns>
    public async Task<bool> Delete(string fileUrl)
    {
        if (string.IsNullOrEmpty(fileUrl)) return false;
        if (fileUrl.Contains("?"))
        {
            fileUrl = fileUrl.Substring(0, fileUrl.LastIndexOf("?"));
        }

        var stroageKey = FileUploadProvider.GetLocalFileStorageKey(fileUrl);
        if (string.IsNullOrEmpty(stroageKey))
        {
            var storage = GetService<IFileStorage>();
            var resource = await storage.GetByPath(fileUrl);
            if (resource == null)
            {
                throw new ArgumentException("文件资源不存在");
            }
            stroageKey = resource.StorageKey;
        }
        IFileUpload service = GetService(stroageKey);
        return await service.Delete(fileUrl);
    }
    /// <summary>
    /// 保存临时文件转为正式文件
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public async Task<bool> SaveTemp(string path)
    {
        if (string.IsNullOrEmpty(path)) return false;
        if (path.Contains("?"))
        {
            path = path.Substring(0, path.LastIndexOf("?"));
        }

        var stroageKey = FileUploadProvider.GetLocalFileStorageKey(path);
        if (string.IsNullOrEmpty(stroageKey))
        {
            var storage = GetService<IFileStorage>();
            var resource = await storage.GetByPath(path);
            if (resource == null)
            {
                throw new ArgumentException("文件资源不存在");
            }
            stroageKey = resource.StorageKey;
        }
        IFileUpload service = GetService(stroageKey);
        return await service.SaveTemp(path);
    }
    /// <summary>
    /// 保存临时文件转为正式文件
    /// </summary>
    /// <param name="paths"></param>
    /// <returns></returns>
    public async Task<bool> SaveTemp(List<string> paths)
    {
        if (paths?.Count <= 0) return false;
        for (int i = 0; i < paths.Count; i++)
        {
            var path = paths[i];
            if (path.Contains("?"))
            {
                path = path.Substring(0, path.LastIndexOf("?"));
            }
            var stroageKey = FileUploadProvider.GetLocalFileStorageKey(path);
            if (string.IsNullOrEmpty(stroageKey))
            {
                var storage = GetService<IFileStorage>();
                var resource = await storage.GetByPath(path);
                if (resource == null)
                {
                    throw new ArgumentException("文件资源不存在");
                }
                stroageKey = resource.StorageKey;
            }
            IFileUpload service = GetService(stroageKey);
            await service.SaveTemp(path);
        }

        return true;
    }


    /// <summary>
    /// 获取IFileUpload服务
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    private IFileUpload GetService(string key)
    {
        Type serviceType = FileUploadProvider.Get(key);
        var firstOrDefault = GetService<IFileUpload>(serviceType);
        if (firstOrDefault == null)
            throw new ArgumentException("" + key + " not found in providers");
        return firstOrDefault;
    }

    /// <summary>
    /// 获取服务
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private T GetService<T>()
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var type = typeof(T);
            return (T)scope.ServiceProvider.GetService(type);
        }
    }


    /// <summary>
    /// 获取服务
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private T GetService<T>(Type targetType)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var type = typeof(T);
            var services = scope.ServiceProvider.GetServices(type);
            var firstOrDefault = services.FirstOrDefault(x => x.GetType() == targetType);
            return (T)firstOrDefault;
        }
    }

    public async Task<MultipartUploadResult> PartUploadAsync(UploadPartInputStream stream)
    {
        if (string.IsNullOrEmpty(stream.StorageKey))
        {
            stream.StorageKey = FileUploadProvider.GetDefaultFileProviderOptions()?.StorageKey;
        }
        IFileUpload service = GetService(stream.StorageKey);
        return await service.PartUploadAsync(stream);
    }

    public async Task<string> FinishMultipartUploadAsync(UploadPartFinishRequest request, Action<FinishUploadResult> callback = null)
    {
        if (string.IsNullOrEmpty(request.StorageKey))
        {
            request.StorageKey = FileUploadProvider.GetDefaultFileProviderOptions()?.StorageKey;
        }
        IFileUpload service = GetService(request.StorageKey);
        return await service.FinishMultipartUploadAsync(request, callback);
    }

    public async Task<bool> DeleteById(string id)
    {
        if (string.IsNullOrEmpty(id)) return false;
        var storage = GetService<IFileStorage>();
        var resource = await storage.Get(id);
        if (resource == null)
        {
            throw new ArgumentException("文件资源不存在");
        }
        var stroageKey = resource.StorageKey;

        IFileUpload service = GetService(stroageKey);
        return await service.DeleteById(id);
    }
}